function dict2goboard(go_dict) {
    var go_board = tf.zeros([19, 19]).arraySync();
    for (var item in go_dict) {
        var row = ascii_to_number(item[0]);
        var col = ascii_to_number(item[1]);
        go_board[row][col] = ascii_to_number(go_dict[item]);
    }
    return tf.tensor(go_board, [19, 19]);
}

function dict2inputShape(go_dict) {
    var go_board = tf.zeros([19, 19]).arraySync();
    for (var r = 0; r < 19; r++) {
        for (var c = 0; c < 19; c++) {
            go_board[r][c] = [1, 0, 0]
        }
    }
    for (var item in go_dict) {
        var row = ascii_to_number(item[0]);
        var col = ascii_to_number(item[1]);
        if (go_dict[item] == go_player) {
            go_board[row][col] = [0, 1, 0];
        } else if (go_dict[item] in simplego.colors) {
            go_board[row][col] = [0, 0, 1];
        }
    }
    return tf.tensor(go_board, [19, 19, 3]);
}

async function modelDownloads() {
    //模型文件下载
    sg_factory.simplego_model.summary();
    await sg_factory.simplego_model.save('downloads://simplego_model');
}

async function modelUpload() {
    console.clear();
    jsonUpload = document.getElementById('json-upload');
    weightsUpload = document.getElementById('weights-upload');
    sg_factory.simplego_model = await tf.loadLayersModel(tf.io.browserFiles([jsonUpload.files[0], weightsUpload.files[0]]));
    sg_factory.simplego_model.compile({
        optimizer: 'sgd',
        loss: 'meanSquaredError',
        metrics: ['accuracy']
    });
    sg_factory.simplego_model.summary();
    status_bar.push("上传模型和权重。");
}

function go_board_transpose(go_board) {
    list_of_go_board = [go_board];
    list_of_go_board.push(go_board.reverse(0));
    list_of_go_board.push(go_board.reverse(1));
    list_of_go_board.push(go_board.transpose([1, 0, 2]));
    list_of_go_board.push(go_board.reverse(0).reverse(1));
    list_of_go_board.push(go_board.reverse(0).transpose([1, 0, 2]));
    list_of_go_board.push(go_board.transpose([1, 0, 2]).transpose([1, 0, 2]));
    list_of_go_board.push(go_board.transpose([1, 0, 2]).reverse(1));
    return list_of_go_board;
}

function go_step_transpose(go_board) {
    list_of_go_board = [go_board];
    list_of_go_board.push(go_board.reverse());
    list_of_go_board.push(go_board.reverse(1));
    list_of_go_board.push(go_board.transpose());
    list_of_go_board.push(go_board.reverse().reverse(1));
    list_of_go_board.push(go_board.reverse().transpose());
    list_of_go_board.push(go_board.transpose().transpose());
    list_of_go_board.push(go_board.transpose().reverse(1));
    return list_of_go_board;
}

class simplego_workshop {
    constructor(name) {
        this.workshopname = name;
    }
    main() {
        throw "没有构建main函数";
    }
}

class model_create extends simplego_workshop {
    constructor() {
        super("模型创建");
        this.simplego_model = tf.sequential();
    }
    main() {
        const inputShape = [1, 19, 19, 3];
        this.simplego_model.add(tf.layers.conv2d({
            filters: 19,
            kernelSize: 3,
            activation: 'relu',
            inputShape: inputShape.slice(1),
            padding: 'valid'
        }));
        this.simplego_model.add(tf.layers.maxPooling2d({ poolSize: 3, strides: 3 }));
        this.simplego_model.add(tf.layers.flatten());
        this.simplego_model.add(tf.layers.dense({ units: 361, activation: 'softmax' }));
        this.simplego_model.compile({
            optimizer: 'sgd',
            loss: 'meanSquaredError',
            metrics: ['accuracy']
        });
        //this.simplego_model.summary();
        return this.simplego_model;
    }
}

class model_fit_all extends simplego_workshop {
    constructor(simplego_model) {
        super("模型训练");
        this.simplego_model = simplego_model;
    }
    async main() {
        status_bar.push("开始训练！");
        var index = 0;
        var go_board = [];
        var go_step = [];
        while (index < simplego_Handle2.goList.length) {
            go_board = go_board.concat(go_board_transpose(dict2inputShape(simplego_Handle2.list_of_parent[index])));
            var item = {};
            item[simplego_Handle2.goList[index].slice(2, 4)] = simplego_Handle2.goList[index][0];
            go_step = go_step.concat(go_step_transpose(dict2goboard(item)));
            index++;
        }
        for (let i = 1; i < 9; ++i) {
            const h = await this.simplego_model.fit(tf.stack(go_board), tf.stack(go_step).reshape([tf.stack(go_step).shape[0], 361]), {
                batchSize: 8,
                epochs: 9
            });
            status_bar.push("Loss after Epoch " + i + " : " + h.history.loss[0]);
        }
        status_bar.push("训练完成！");
    }
}

class model_fit_last extends simplego_workshop {
    constructor(simplego_model) {
        super("模型训练");
        this.simplego_model = simplego_model;
    }
    async main() {
        status_bar.push("开始训练！");
        var index = 0;
        var go_board = go_board_transpose(dict2inputShape(simplego_Handle2.list_of_parent.at(-1)));
        var item = {};
        item[simplego_Handle2.goList.at(-1).slice(2, 4)] = simplego_Handle2.goList.at(-1)[0];
        var go_step = go_step_transpose(dict2goboard(item));
        for (let i = 1; i < 3; ++i) {
            const h = await this.simplego_model.fit(tf.stack(go_board), tf.stack(go_step).reshape([tf.stack(go_step).shape[0], 361]), {
                batchSize: 8,
                epochs: 3
            });
            status_bar.push("Loss after Epoch " + i + " : " + h.history.loss[0]);
        }
        status_bar.push("训练完成！");
    }
}

class model_predict extends simplego_workshop {
    constructor(simplego_model) {
        super("模型预测");
        this.simplego_model = simplego_model;
    }
    async main() {
        var mp = this.simplego_model.predict(dict2inputShape(simplego_Handle2.list_of_parent.at(-1)).expandDims()).flatten();
        var gbtf = dict2goboard(simplego_Handle2.list_of_parent.at(-1)).flatten();
        var mpw = tf.where(tf.equal(gbtf, tf.scalar(0)), mp, tf.zeros([361]));
        var mp_list = [];
        for (var i in mpw.arraySync()) {
            var dict = { index: 0, value: 0 }
            dict["index"] = i;
            dict["value"] = mpw.arraySync()[i]
            mp_list.push(dict);
        }
        mp_list.sort(function (a, b) {
            return b["value"] - a["value"]
        });
        mp_list.slice(0, 3).forEach((item) => {
            var c = item["index"] % 19
            var r = (item["index"] - c) / 19;
            var pos = simplego.positions[r] + simplego.positions[c];
            status_bar.push(pos + ", " + item["value"]);
        });
    }
}

class simplego_factory {
    constructor() {
        this.sg_factory = {};
        let sgf = new model_create();
        this.simplego_model = sgf.main();
        this.sg_factory["sw_model_fit_last"] = new model_fit_last(this.simplego_model);
        this.sg_factory["sw_model_predict"] = new model_predict(this.simplego_model);
    }
    async main() {
        //console.clear();
        for (var sgf in this.sg_factory) {
            this.sg_factory[sgf].main();
        }
    }
}
let sg_factory = new simplego_factory();
